/* 
 * File:   RapidStopper.cpp
 * Author: dell
 * 
 * Created on 2012年4月5日, 下午6:46
 */

#include <vector>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/wait.h>
//#include <wait.h>
#include <signal.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <sys/types.h>
#include <dirent.h>
#include <cerrno>

#include "RapidStopper.h"

using namespace std;

namespace Rapid{
    RapidStopper::RapidStopper(const char* homeDir, int port):
    serverPid(homeDir, port), homeDir(homeDir), port(port), pid(-1)
    {

    }

    RapidStopper::~RapidStopper() {
    }
    
    /** 停止所有正在运行的服务 */
    int RapidStopper::killAll(const char* homeDir){
        return stopAll(homeDir, true);
    }
    
    /** 停止所有正在运行的服务 */
    int RapidStopper::stopAll(const char* homeDir){
        return stopAll(homeDir, false);
    }
    
    /** 停止所有正在运行的服务 */
    int RapidStopper::stopAll(const char* homeDir, bool kill){
        //读homeDir/conf目录下的server_*.pid文件
        DIR* confDir = opendir(string(homeDir).append("conf/").c_str());
        if(!confDir){
            LOG_ERROR("open conf dir failure, homeDir is %s, errno:%d", homeDir, errno);
            return 1;
        }

        vector<RapidStopper*> rapidStoppers;
        do{
            struct dirent* dirent = readdir(confDir);
            if(!dirent){
                break;
            }
            static const char* prefix = "server_";
            static const char* suffix = ".pid";
            static int prefixLen =  strlen(prefix);
            static int suffixLen =  strlen(suffix);

            int filenameLen = strlen(dirent->d_name);
            if(filenameLen > (prefixLen+suffixLen) && 
                    strncmp(dirent->d_name, prefix, prefixLen) == 0 && 
                    strncmp(dirent->d_name + (filenameLen-suffixLen), suffix, suffixLen) == 0){
                int port = atoi((string(dirent->d_name).substr(prefixLen, (filenameLen-(prefixLen+suffixLen)))).c_str());
                RapidStopper* rapidStopper = new RapidStopper(homeDir, port);
                if(kill){
                    rapidStopper->killServer();
                }else{
                    rapidStopper->notifyStop();
                }
                rapidStoppers.push_back(rapidStopper);

            }

        }while(1);
        closedir(confDir);

        if(rapidStoppers.empty()){
            cout<<"server no started!"<<endl;
            return 1;
        }

        if(kill){
            vector<RapidStopper*>::iterator it = rapidStoppers.begin();
            for(; it != rapidStoppers.end(); it++){
                RapidStopper* rapidStopper = (*it);
                rapidStopper->removeFile();
            }
        }
        return 0;
    }
    
    
    
    bool RapidStopper::killServer(){
        LOG_DEBUG("pid:%d",pid);
        if(!readPid()){
            return false;
        }
        LOG_DEBUG("pid:%d",pid);
        ::kill(pid, SIGKILL);
        return true;
    }    
    
    bool RapidStopper::notifyStop(){
        LOG_DEBUG("pid:%d",pid);
        if(!readPid()){
            return false;
        }
        LOG_DEBUG("pid:%d",pid);
        ::kill(pid, SIGTERM);
        return true;
    }
    
    bool RapidStopper::removeFile(){
        LOG_DEBUG("%s", serverPid.getServerPidFilename());
        return serverPid.remove();
    }
    
    bool RapidStopper::readPid(){
        if(pid < 0){
            pid = serverPid.read();
            if(pid < 0){
                LOG_WARN("read pid error from %s ", serverPid.getServerPidFilename());
                return false;
            }
        }
        return true;
    }
}


